/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Practica1.practica;

import Practica1.util.Edge;
import Practica1.util.Graph;
import Practica1.util.Vertex;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author miguel
 */
public class MyGraph implements Graph {

    private List<MyVertex> listVertex;
    private List<MyEdge> listEdges;
    private boolean isDirected;
    private String fileName;
    private int indexEdge;
    private boolean[][] adjacencyMatrix;
    private int indexVertex;

    public boolean isIsDirected() {
        return isDirected;
    }

    public MyGraph(String fileName) {
        listVertex = new ArrayList<>();
        listEdges = new ArrayList<>();
        isDirected = false;
        this.fileName = fileName;
        indexEdge = 0;
        indexVertex = 0;
        readFile();
    }

    /**
     * Método privado para leer desde el archivo el conjunto de datos
     *
     */
    private boolean readFile() {
        if (fileName.equals("")) {
            System.out.println("Nombre Vacío");
            return false;
        } else {
            BufferedReader br;
            String line;
            try {
                br = new BufferedReader(new FileReader(fileName));
                try {
                    line = br.readLine();
                    if (!line.split(",")[0].trim().equals("graph") && !line.split(",")[1].trim().equals("directed")) {

                        System.out.println(line.split(",")[0].trim() + " " + line.split(",")[1].trim());
                        return false;
                    }
                    if (line.split(",")[2].trim().equals("true")) {
                        isDirected = true;
                    }else{
                        isDirected = false;
                    }
                    String[] lineSplit;

                    while ((line = br.readLine()) != null) {
                        //System.out.println(line);
                        lineSplit = line.split(",");
                        switch (lineSplit[0].trim()) {
                            case "vertex":
                                boolean exists = false;
                                for (Vertex v : listVertex) {
                                    if (v.getElement().equals(lineSplit[2].trim()) && v.getColor() == Integer.parseInt(lineSplit[4].trim())) {
                                        exists = true;
                                    }
                                }
                                if (exists) {
                                    break;
                                }
                                MyVertex v = new MyVertex(lineSplit[2].trim(), indexVertex++);
                                v.setColor(Integer.parseInt(lineSplit[4].trim()));
                                listVertex.add(v);
                                break;
                            case "edge":
                                MyVertex source = null,
                                 target = null;
                                for (Vertex vertex : listVertex) {
                                    
                                    if (((String) vertex.getElement()).equals(lineSplit[2])) {
                                        source = (MyVertex) vertex;
                                    } else if (((String) vertex.getElement()).equals(lineSplit[4])) {
                                        target = (MyVertex) vertex;
                                    }
                                }
                                if (isDirected) {
                                    source.addNeighbour(target);
                                    MyEdge e = new MyEdge(source, target, Integer.parseInt(lineSplit[6].trim()), indexEdge++, Integer.parseInt(lineSplit[8].trim()));
                                    listEdges.add(e);
                                } else {
                                    source.addSymmetricNeighbour(target);
                                    MyEdge e1 = new MyEdge(source, target, Integer.parseInt(lineSplit[6].trim()), indexEdge++, Integer.parseInt(lineSplit[8].trim()));
                                    listEdges.add(e1);
                                    //Edge e2 = new Edge(target,source,Integer.parseInt(lineSplit[6].trim()),Integer.parseInt(lineSplit[8].trim()));
                                    //listEdges.add(e2);
                                }

                                break;
                        }
                    }
                    matrixFilled();
                } catch (IOException ex) {
                    Logger.getLogger(MyGraph.class.getName()).log(Level.SEVERE, null, ex);
                    System.out.println("Error entrada salida");
                }
                return true;
            } catch (FileNotFoundException ex) {
                Logger.getLogger(MyGraph.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("Error archivo no encontrado");
            }
            return false;
        }
    }

    /**
     * Método privado para rellenar la matriz de incidencia
     */
    private void matrixFilled() {
        int i, j;
        adjacencyMatrix = new boolean[listVertex.size()][listVertex.size()];
        for (Edge edge : listEdges) {
            i = edge.getSource().getIndex();
            j = edge.getTarget().getIndex();
            adjacencyMatrix[i][j] = true;
            adjacencyMatrix[j][i] = true;
        }
    }

    /**
     * Representación de la matriz de adyacencia
     *
     * @return matriz de adyacencia
     */
    public String matrixRepresentation() {
        String s = "Matriz de adyacencia\nTu gráfica es: ";
        if (isDirected) {
            s += "dirigida\n";
        } else {
            s += "no dirigida\n\t";
        }

        for (Vertex v : listVertex) {
            s += (String) v.getElement() + "\t\t";
        }
        s += "\n";
        for (int i = 0; i < adjacencyMatrix.length; i++) {
            for (int j = 0; j < adjacencyMatrix[i].length; j++) {
                if (j == 0) {
                    s += (String) listVertex.get(i).getElement();
                }
                if (adjacencyMatrix[i][j] == true) {
                    s += "\t{" + i + "," + j + "} 1, peso: " + this.getWeight(i, j) + ", color: " + this.getColor(i, j);
                } else {
                    s += "\t{" + i + "," + j + "} 0, peso: 0, color: 0";
                }
            }
            s += "\n";
        }
        return s;
    }

    /**
     * Establece el nombre del archivo
     *
     * @param fileName nombre del archivo
     */
    public void setFileName(String fileName) {
        this.fileName = fileName;
        readFile();
    }

    /**
     * Regresa el color de la arista i, j
     *
     * @param start
     * @param end
     * @return
     */
    private int getColor(int start, int end) {
        if (!isDirected) {
            for (MyEdge e : listEdges) {
                if (e.getSource().getIndex() == start && e.getTarget().getIndex() == end || e.getSource().getIndex() == end && e.getTarget().getIndex() == start) {
                    return e.getColor();
                }
            }
        } else {
            for (MyEdge e : listEdges) {
                if (e.getSource().getIndex() == start && e.getTarget().getIndex() == end) {
                    return e.getColor();
                }
            }
        }
        return 0;
    }

    @Override
    public int getVertexNum() {
        return listVertex.size();
    }

    @Override
    public int getEdgesNum() {
        return listEdges.size();
    }

    @Override
    public List getVertexList() {
        return listVertex;
    }

    @Override
    public Vertex[] getVertexArray() {
        return (Vertex[]) listVertex.toArray();
    }

    @Override
    public Vertex getVertex(int i) {
        return listVertex.get(i);
    }

    @Override
    public List getEdgesList() {
        return listEdges;
    }

    @Override
    public Edge[] getEdgesArray() {
        return (Edge[]) listEdges.toArray();
    }

    @Override
    public Edge getEdge(Vertex start, Vertex end) {
        Edge edge = null;
        if (isDirected) {
            for (MyEdge e : listEdges) {
                if (e.getSource().equals(start) && e.getTarget().equals(end)) {
                    return e;
                }
            }
        }else{
            for (MyEdge e : listEdges) {
                if ((e.getSource().equals(start) && e.getTarget().equals(end))) {
                    return e;
                }else if( (e.getSource().equals(end) && e.getTarget().equals(start))){
                    
                    return e;
                }
            }
        }

        return edge;
    }

    @Override
    public Edge getEdge(int i) {
        return listEdges.get(i);
    }

    @Override
    public boolean isAdjacent(Vertex start, Vertex end) {
        Edge e = this.getEdge(start, end);
        if (e.getTarget() != null && e.getSource() != null) {
            return true;
        }

        return false;
    }

    @Override
    public boolean isAdjacent(int i, int j) {
        Vertex v1 = listVertex.get(i);
        Vertex v2 = listVertex.get(j);
        Edge e = this.getEdge(v1, v2);
        if (e.getSource() != null && e.getTarget() != null) {
            return true;
        }
        return false;
    }

    @Override
    public int getDegree(Vertex v) {
        return v.grade();
    }

    @Override
    public int getDegree(int i) {
        return listVertex.get(i).grade();
    }

    @Override
    public int getWeight(Edge e) {
        return e.getWeight();
    }

    @Override
    public int getWeight(Vertex start, Vertex end) {
        return getEdge(start, end).getWeight();
    }

    @Override
    public int getWeight(int start, int end) {
        Vertex v1 = this.getVertex(start);
        Vertex v2 = this.getVertex(end);
        return getEdge(v1, v2).getWeight();
    }

    @Override
    public Vertex[] getNeighborsArray(Vertex v) {
        return (Vertex[]) v.getNeighboursList().toArray();
    }

    @Override
    public Vertex[] getNeighborsArray(int i) {
        return (Vertex[]) listVertex.get(i).getNeighboursList().toArray();
    }

    @Override
    public List getNeighborsList(Vertex v) {
        return v.getNeighboursList();
    }

    @Override
    public List getNeighborsList(int i) {
        return listVertex.get(i).getNeighboursList();
    }
}
